home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Dev / Amiga-E / E_v3.2a / Src / Utils / D.e < prev    next >
Text File  |  1992-09-02  |  11KB  |  298 lines

  1. /* recursive directory tool
  2.  
  3. needs v37.
  4.  
  5. Universal directory lister. called with no arguments, by just typing
  6. "d", it lists the current directory. template:
  7.  
  8. DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,FULL/S,NOANSI/S,
  9. TARGET/K,DO/K/F
  10.  
  11. DIR        specifies an optional path to the dir you wish to list.
  12.         may contain standard wildcard patterns like #?~[]%() etc.
  13. REC        specifies that subdirectories should be listed recursively.
  14. WIDTH <num>    max width of one line of output. if not present, D will
  15.         infer this from the current width of the console.
  16.         NOTE: currently it just takes WIDTH=77 as default. does anyone
  17.         have code that gets the width from the console?
  18. COL <num>    where n=1..10, by default, D will try and fit as many
  19.         columns as allowed by WIDTH.
  20. SIZE        reports the size of each dir as it is being listed. note that
  21.         combined with REC gives sizes of whole dir (sub-)trees.
  22. NOSORT        by default, dirs are sorted before display. disable this with
  23.         the NOSORT switch.
  24. NOFILES        displays just dirs
  25. NODIRS        displays just files
  26. FULL        lists full path instead of just filename
  27. NOANSI        doesn't use ansi display codes while printing
  28. TARGET <dir>    specifies a target directory for use with DO. should
  29.         end in either "/" or ":"
  30. DO <comline>    specifies a commandline for automatic script generation.
  31.         note that this uses up the rest of D's commandline.
  32.  
  33. something should be said on the script feature: it enables you
  34. to perform repetitive tasks on whole dirs, or dir-trees. existing
  35. utilities that enabled you to do such tasks where mostly not
  36. flexible enough; d enables you to use the REC keyword in combination
  37. with scripts, allows for variable extensions: use <file>.o if
  38. the original name was <file>.s, and the spec. of a target:
  39. resulting files from the operation are placed in another dir, which
  40. can be a complete mirror image of another dir-tree. makedir
  41. statements are inserted if target: is empty.
  42.  
  43. following format codes may be used in <commandline>:
  44.  
  45. %s is file (filename+path)
  46. %f is file WITHOUT extension
  47. %r is file without extension, but with leading <dir> replaced by
  48.    <target> (usefull if <commandline> allows for an outputfile)
  49. %> or %< %>> etc. prevents the shell from thinking ">" is a redirection
  50.    for D, instead of <commandline>
  51.  
  52. a complex example:
  53. you wish to have a complete ascii reference of the emodules:
  54. directory, recursively, and with the resulting .txt files
  55. as a mirror-image directory structure somewhere else.
  56.  
  57. 1> D >ram:script emodules: REC TARGET=t:mods/ DO showmodule %>%r.txt %s
  58. 1> execute ram:script
  59.  
  60. will do that for you.
  61. for any file like "emodules:exec/io.m" D will make a line like:
  62. "showmodule  >t:mods/exec/io.txt emodules:exec/io.m"
  63.  
  64. other examples:    D >mydirlist dh0: WIDTH=100 SIZE REC NOANSI
  65.         D docs: DO type >prt: %s
  66.         D asm: TARGET=obj: DO genam %s -o%r.o
  67.         D emodules: REC TARGET=ram: DO showmodule %>%r.txt %s
  68.  
  69. */
  70.  
  71. OPT OSVERSION=37
  72.  
  73. CONST MAXPATH=250
  74.  
  75. ENUM ER_NONE,ER_BADARGS,ER_MEM,ER_UTIL,ER_ITARG,ER_COML
  76. ENUM ARG_DIR,ARG_REC,ARG_WIDTH,ARG_COL,ARG_SIZE,ARG_NOSORT,ARG_NOFILES,
  77.      ARG_NODIRS,ARG_FULL,ARG_NOANSI,ARG_TARGET,ARG_COMMAND,NUMARGS
  78.  
  79. MODULE 'dos/dosasl', 'dos/dos', 'utility', 'intuition/intuitionbase',
  80.        'intuition/intuition', 'graphics/gfxbase', 'graphics/text'
  81.  
  82. RAISE ER_MEM IF New()=NIL,      /* set common exceptions:                */
  83.       ER_MEM IF String()=NIL,      /* every call to these functions will be */
  84.       ERROR_BREAK IF CtrlC()=TRUE /* automatically checked against NIL,    */
  85.                   /* and the exception ER_MEM is raised    */
  86.  
  87. DEF dir,command,target,
  88.     recf=FALSE,col=3,calccolf=TRUE,comf=FALSE,sizef=FALSE,sortf=TRUE,filesf=TRUE,
  89.     fullf=FALSE,ansif=TRUE,dirsf=TRUE,dirw[100]:STRING,
  90.     rdargs=NIL,work[250]:STRING,work2[250]:STRING,dirno=0,
  91.     prtab[25]:LIST,prcopy[25]:LIST,workdir[250]:STRING,
  92.     consolewidth=0
  93.  
  94. PROC main() HANDLE
  95.   DEF args[NUMARGS]:LIST,templ,x,lock,fib:fileinfoblock,s
  96.   IF (utilitybase:=OpenLibrary('utility.library',37))=NIL THEN Raise(ER_UTIL)
  97.   FOR x:=0 TO NUMARGS-1 DO args[x]:=0
  98.   templ:='DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,' +
  99.          'FULL/S,NOANSI/S,TARGET/K,DO/K/F'
  100.   rdargs:=ReadArgs(templ,args,NIL)
  101.   IF rdargs=NIL THEN Raise(ER_BADARGS)        /* initialise flags */
  102.   IF args[ARG_SIZE] THEN sizef:=TRUE        /* from command line args */
  103.   consolewidth:=Bounds(IF args[ARG_WIDTH] THEN Long(args[ARG_WIDTH]) ELSE findconsolewidth(),1,1000)
  104.   IF args[ARG_COL] THEN (calccolf:=FALSE) BUT col:=Long(args[ARG_COL])
  105.   col:=Bounds(col,1,100)
  106.   IF args[ARG_NOSORT] THEN sortf:=FALSE
  107.   IF args[ARG_NOANSI] THEN ansif:=FALSE
  108.   IF args[ARG_NOFILES] THEN filesf:=FALSE
  109.   IF args[ARG_NODIRS] THEN dirsf:=FALSE
  110.   IF args[ARG_REC] THEN recf:=TRUE
  111.   IF args[ARG_FULL] THEN fullf:=TRUE
  112.   target:=args[ARG_TARGET]
  113.   command:=args[ARG_COMMAND]
  114.   IF command THEN comf:=TRUE
  115.   IF target
  116.     x:=target+StrLen(target)-1
  117.     IF (x<target) OR ((x[]<>":") AND (x[]<>"/")) THEN Raise(ER_ITARG)
  118.   ENDIF
  119.   IF comf
  120.     sortf:=FALSE    /* read and convert commandline for scripts */
  121.     col:=1
  122.     filesf:=FALSE
  123.     dirsf:=FALSE
  124.     IF command[]=0 THEN Raise(ER_COML)
  125.     s:=command
  126.     WHILE x:=s[]++
  127.       IF x="%"
  128.         x:=s[]
  129.         SELECT x
  130.           CASE "s"; ListAdd(prtab,[1],1)            /* %s = fullpath */
  131.           CASE "f"; ListAdd(prtab,NEW [work],1); s[]:="s"    /* %f = work     */
  132.           CASE "r"; ListAdd(prtab,NEW [work2],1); s[]:="s"    /* %r = work2    */
  133.           DEFAULT; s[-1]:=" "
  134.         ENDSELECT
  135.       ENDIF
  136.     ENDWHILE
  137.   ENDIF
  138.   dir:=args[ARG_DIR]
  139.   IF dir THEN StrCopy(dirw,dir,ALL)
  140.   lock:=Lock(dirw,-2)
  141.   IF lock                  /* if yes, the prob. dir, else wildcard */
  142.     IF Examine(lock,fib) AND (fib.direntrytype>0)
  143.       AddPart(dirw,'#?',100)
  144.     ENDIF
  145.     UnLock(lock)
  146.   ENDIF
  147.   recdir(dirw)
  148.   Raise(ER_NONE)
  149. EXCEPT
  150.   IF rdargs THEN FreeArgs(rdargs)
  151.   IF utilitybase THEN CloseLibrary(utilitybase)
  152.   SELECT exception
  153.     CASE ER_BADARGS;            PrintF('Bad Arguments for D!\n')
  154.     CASE ER_MEM;                PrintF('No mem!\n')
  155.     CASE ER_COML;               PrintF('No commandline specified\n')
  156.     CASE ER_ITARG;              PrintF('Illegal target\n')
  157.     CASE ER_UTIL;               PrintF('Could not open "utility.library" v37\n')
  158.     CASE ERROR_BREAK;           PrintF('User terminated D\n')
  159.     CASE ERROR_BUFFER_OVERFLOW; PrintF('Internal error\n')
  160.     DEFAULT;                    PrintFault(exception,'Dos Error')
  161.   ENDSELECT
  162. ENDPROC
  163.  
  164. PROC recdir(dirr) HANDLE
  165.   DEF er,i:PTR TO fileinfoblock,size=0,anchor=NIL:PTR TO anchorpath,fullpath,
  166.       flist=NIL,first,entries=0,ascii,w,x,y,z,flist2=NIL,
  167.       isfirst=0,maxfilename=1,maxfilesize=-1,lcol
  168.   anchor:=New(SIZEOF anchorpath+MAXPATH)
  169.   anchor.breakbits:=4096
  170.   anchor.strlen:=MAXPATH-1
  171.   er:=MatchFirst(dirr,anchor)            /* collect all strings */
  172.   WHILE er=0
  173.     fullpath:=anchor+SIZEOF anchorpath
  174.     i:=anchor.info
  175.     ascii:=IF fullf THEN fullpath ELSE i.filename
  176.     IF i.direntrytype>0 
  177.       StringF(work,'\s\l\s[30]         ',IF ansif THEN '\e' ELSE '',ascii)
  178.     ELSE
  179.       StringF(work,'\l\s[30] \r\d[8]',ascii,i.size)
  180.       IF i.size>maxfilesize THEN maxfilesize:=i.size
  181.     ENDIF
  182.     x:=StrLen(ascii)
  183.     IF x>maxfilename THEN maxfilename:=x
  184.     IF IF i.direntrytype>0 THEN dirsf ELSE filesf
  185.       first:=String(EstrLen(work))
  186.       StrCopy(first,work,ALL)
  187.       flist:=Link(first,flist)
  188.       INC entries
  189.     ENDIF
  190.     IF i.direntrytype<0 THEN size:=size+i.size
  191.     IF (i.direntrytype<0) AND comf        /* execute commandline */
  192.       ListCopy(prcopy,prtab,ALL)
  193.       IF comf THEN MapList({x},prcopy,prcopy,`IF x=1 THEN fullpath ELSE x)
  194.       StrCopy(work,fullpath,ALL)
  195.       x:=InStr(work,'.',0)
  196.       IF x<>-1 THEN SetStr(work,x)        /* find f% */
  197.       IF target
  198.         StrCopy(work2,target,ALL)
  199.         x:=work; y:=dirw        /* was dirr */
  200.         WHILE x[]++=y[]++ DO NOP
  201.         DEC x
  202.         StrAdd(work2,x,ALL)            /* find r% */
  203.       ELSE
  204.         StrCopy(work2,work,ALL)
  205.       ENDIF
  206.       IF isfirst++=0
  207.         StrCopy(workdir,work2,ALL)        /* see if makedir is needed */
  208.         SetStr(workdir,PathPart(work2)-work2)
  209.         x:=Lock(workdir,-2)
  210.         IF x THEN UnLock(x) ELSE PrintF('makedir \s\n',workdir)
  211.       ENDIF
  212.       Flush(stdout); VfPrintf(stdout,command,prcopy); Flush(stdout)
  213.       PrintF('\n')
  214.     ENDIF
  215.     IF recf AND (i.direntrytype>0)        /* do recursion(=tail) */
  216.       x:=StrLen(fullpath)
  217.       IF x+5<MAXPATH THEN CopyMem('/#?',fullpath+x,4)
  218.       size:=size+recdir(fullpath)
  219.       fullpath[x]:=0
  220.     ENDIF
  221.     er:=MatchNext(anchor)
  222.   ENDWHILE
  223.   IF er<>ERROR_NO_MORE_ENTRIES THEN Raise(er)
  224.   MatchEnd(anchor)
  225.   Dispose(anchor)
  226.   anchor:=NIL
  227.   maxfilesize:=IF maxfilesize>=0 THEN sillylog10(maxfilesize) ELSE 0
  228.   lcol:=Bounds(IF calccolf THEN consolewidth+1/(maxfilesize+maxfilename+2) ELSE col,1,100)
  229.   flist:=Link(String(1),flist)
  230.   IF entries>2 AND sortf THEN flist:=sort(flist)
  231.   IF comf=FALSE                        /* display dir */
  232.     IF dirno THEN PrintF('\n')
  233.     PrintF(IF ansif THEN '\e[1mDirectory of: "\s"\e[0m\n' ELSE 'Directory of: "\s"\n',dirr)
  234.   ENDIF
  235.   first:=flist
  236.   x:=entries/lcol          /* put dirlist in columns */
  237.   IF x*lcol<entries THEN INC x
  238.   FOR z:=1 TO x
  239.     first:=Next(first)
  240.     flist2:=first
  241.     FOR y:=1 TO lcol
  242.       IF flist2
  243.         w:=maxfilename
  244.         IF flist2[]="\e"
  245.           flist2[w+1]:=0
  246.           IF ansif THEN PutStr('\e[1;32m')
  247.           PrintF('\s \s',flist2+1,flist2+40-maxfilesize)
  248.           IF ansif THEN PutStr('\e[0;31m')
  249.         ELSE
  250.           flist2[w]:=0
  251.           PrintF('\s \s',flist2,flist2+39-maxfilesize)
  252.         ENDIF
  253.         flist2:=Forward(flist2,x)
  254.         IF y<>lcol THEN PrintF(' ')
  255.       ENDIF
  256.     ENDFOR
  257.     PrintF('\n')
  258.     CtrlC()
  259.   ENDFOR
  260.   IF sizef THEN PrintF('BYTE SIZE: \d\n',size)
  261.   DisposeLink(flist)
  262.   INC dirno
  263. EXCEPT                                  /* nested exception handlers! */
  264.   IF anchor THEN MatchEnd(anchor)
  265.   Raise(exception)  /* this way, we call _all_ handlers in the recursion  */
  266. ENDPROC size        /* and thus calling MatchEnd() on all hanging anchors */
  267.  
  268. PROC sort(flist)
  269.   DEF sortdone,prev,first,next,nnext
  270.   REPEAT
  271.     sortdone:=TRUE                /* sort dirlist */
  272.     prev:=first:=flist
  273.     WHILE first:=Next(first)
  274.       IF next:=Next(first)
  275.         IF Stricmp(first,next)>0
  276.           nnext:=Next(next)
  277.           Link(prev,first:=Link(next,Link(first,nnext)))
  278.           sortdone:=FALSE
  279.         ENDIF
  280.       ENDIF
  281.       prev:=first
  282.     ENDWHILE
  283.     CtrlC()
  284.   UNTIL sortdone
  285. ENDPROC flist
  286.  
  287. PROC findconsolewidth()
  288.   DEF ib:PTR TO intuitionbase,gb:PTR TO gfxbase,w,fw
  289.   ib:=intuitionbase
  290.   gb:=gfxbase
  291.   Forbid()
  292.     w:=ib.activewindow.width
  293.     fw:=gb.defaultfont.xsize
  294.   Permit()
  295. ENDPROC Bounds(w-24/fw,5,250)
  296.  
  297. PROC sillylog10(n) IS IF n<10 THEN 1 ELSE sillylog10(Div(n,10))+1
  298.